package com.yao2san.simdif.service.synchronizer;

import com.yao2san.simdif.entity.ColumnInfo;
import com.yao2san.simdif.entity.TableInfo;
import com.yao2san.simdif.service.DatasourceConnectHelper;

import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;

/**
 * 数据源同步器。不同数据库类型，需要实现该类
 *
 * @author wxg
 */
public abstract class AbstractDatasourceSynchronizer implements DatasourceSynchronizer {
    private Driver driver;
    private final String url;
    private final Properties properties;
    private String user;
    private String password;
    private Connection connection;

    private final static int LOGIN_TIMEOUT = 10;

    protected AbstractDatasourceSynchronizer(String url, String user, String password) {
        this.url = url;
        this.user = user;
        this.password = password;
        this.properties = new Properties();
        this.registerDriverAndGetConnection();
    }

    protected AbstractDatasourceSynchronizer(String url, Properties properties) {
        this.url = url;
        this.properties = properties;
        this.registerDriverAndGetConnection();
    }

    private void registerDriverAndGetConnection() {
        try {
            this.registerDriver();
            this.connection = getConnection();
        } catch (SQLException | ClassNotFoundException |
                 InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void registerDriver() throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        URL resource = Thread.currentThread().getContextClassLoader().getResource(getDriverFile());
        URLClassLoader ucl = new URLClassLoader(new URL[]{resource});
        Driver driver = (Driver) Class.forName(getDriverClassName(), true, ucl).newInstance();
        DriverInstance driverInstance = new DriverInstance(driver);
        DriverManager.registerDriver(driverInstance);
        this.driver = driver;
    }

    @Override
    public void unregisterDriver(Driver driver) throws SQLException {
        DriverManager.deregisterDriver(driver);
    }

    public Connection getConnection() throws SQLException {
        if (this.user != null) {
            properties.put("user", user);
        }
        if (this.password != null) {
            properties.put("password", password);
        }
        DriverManager.setLoginTimeout(LOGIN_TIMEOUT);
        return DriverManager.getConnection(url, properties);
    }

    @Override
    public List<TableInfo> getTables(String database) {
        return this.getTables(connection, database);
    }

    @Override
    public List<ColumnInfo> getColumns(String database, String tableName) {
        return this.getColumns(connection, database, tableName);
    }

    @Override
    public void close() throws SQLException {
        if (driver != null) {
            if (connection != null) {
                if (!connection.isClosed()) {
                    connection.close();
                }
            }
            unregisterDriver(driver);
            DatasourceConnectHelper.removeConnectionAttr();
        }
    }

    /**
     * 获取表信息
     *
     * @param connection 连接
     * @param database   数据库名称
     * @return 表信息
     */
    protected abstract List<TableInfo> getTables(Connection connection, String database);

    /**
     * 获取表信息
     *
     * @param connection 连接
     * @param database   数据库名称
     * @param tableName  表名称
     * @return 表信息
     */
    protected abstract List<ColumnInfo> getColumns(Connection connection, String database, String tableName);

    /**
     * 获取驱动文件
     *
     * @return 驱动文件路径
     */
    public abstract String getDriverFile();

    /**
     * 获取驱动类名
     *
     * @return 驱动类名
     */
    public abstract String getDriverClassName();

}
